

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import ArthDecode.ArithmeticDecoder;
import ArthDecode.BitInputStream;
import ArthDecode.BitOutputStream;
import ArthDecode.FlatFrequencyTable;
import ArthDecode.FrequencyTableA;
import ArthDecode.SimpleFrequencyTable;

public class MAIN {

	/**
	 * @param args
	 * @throws IOException 
	 */
	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		
		Encode("input.txt","compressed.bin");
		Convert("compressed.bin","compressed.txt");
		Decode("compressed.bin","output.txt");
	}

	
public static void Encode(String input, String output) throws IOException {
		
		File inputFile = new File(input);
		File outputFile = new File(output);
		outputFile.createNewFile();
		InputStream in = new BufferedInputStream(new FileInputStream(inputFile));
		BitOutputStream out = new BitOutputStream(new BufferedOutputStream(new FileOutputStream(outputFile)));
			
		compress(in, out);
		out.close();
		in.close();
	}
	
	
	static void compress(InputStream in, BitOutputStream out) throws IOException {
		int[] initFreqs = new int[257];
		Arrays.fill(initFreqs, 1);
		
		FrequencyTable freqTable = new FrequencyTable(initFreqs);
		HuffmanEncoder enc = new HuffmanEncoder(out);
		enc.codeTree = freqTable.buildCodeTree();  
		int count = 0;
		while (true) {
			int b = in.read();
			if (b == -1)
				break;
			enc.write(b);
			
			freqTable.increment(b);
			count++;
			if (count < 262144)  // Update code tree
				enc.codeTree = freqTable.buildCodeTree();
			else   // Reset frequency table
				freqTable = new FrequencyTable(initFreqs);
		}
		enc.write(256);  // EOF
	}
	
	public static void Decode(String input, String output) throws IOException {


		File inputFile = new File(input);
		File outputFile = new File(output);
		outputFile.createNewFile();	
		
		BitInputStream in = new BitInputStream(new BufferedInputStream(new FileInputStream(inputFile)));
		OutputStream out = new BufferedOutputStream(new FileOutputStream(outputFile));
		try {
			decompress(in, out);
		} finally {
			out.close();
			in.close();
		}
	}
	
	
	static void decompress(ArthDecode.BitInputStream in, OutputStream out) throws IOException {
		FrequencyTableA freq = new SimpleFrequencyTable(new FlatFrequencyTable(257));  // Initialize with all symbol frequencies at 1
		ArithmeticDecoder dec = new ArithmeticDecoder(in);
		while (true) {
			int symbol = dec.read(freq);
			if (symbol == 256)  // EOF symbol
				break;
			out.write(symbol);
			freq.increment(symbol);
		}
		
	}
	
	private static void Convert(String Bin, String Text) throws IOException {
		// TODO Auto-generated method stub

		InputStream in = new FileInputStream(Bin);

		
		FileWriter outFile = new FileWriter(Text);
		PrintWriter out = new PrintWriter(outFile);
		
		byte[] buf = new byte[2048];
		int len;
		
		
		    String result = "";
		    while ((len = in.read(buf))>0)
		    {
		    	//inversing the output of huffman each "1" become "0" and opposite
				for (int i = 0 ; i<len ; i++ )
				{
				        result += (buf[i] & (1 << i)) == 0 ? "1" : "0";
				     
				}
				
//		    	for (byte x : buf)


			System.out.println("result: "+result);
			System.out.println("len: "+len);
		    }
			out.write(result);
		in.close();
		out.close();
	}
}
